#include<netinet/in.h>   // sockaddr_in
#include<sys/types.h>    // socket
#include<sys/socket.h>   // socket
#include<stdio.h>        // printf
#include<stdlib.h>       // exit
#include<string.h>       // bzero
#include<unistd.h>
#include<arpa/inet.h>
#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
#include <NTL/ZZ.h>
#include <NTL/BasicThreadPool.h>
#include <NTL/lzz_pXFactoring.h>
#include "FHE.h"
#include "timing.h"
#include "EncryptedArray.h"
#include <cassert>
#include <cstdio>
#include <iostream>
#include<fstream>
using namespace std;
int opnum[10000];                                   
//存放操作数                          
// ctxt ea;
int count=0;  
Ctxt FHE_Enc(long num, const FHEPubKey& publicKey)
{
	Ctxt Enc(publicKey);
	Vec<ZZ> v;
	v.SetLength(2);
	v[0] = num;
	v[1] = 1;
	publicKey.Encrypt(Enc, to_ZZX(v));
	return Enc;
}
long FHE_Dec(Ctxt ctxt, long p, const FHESecKey& secretKey)
{
	long Dec;
	ZZX ptxt;
	secretKey.Decrypt(ptxt, ctxt);
	conv(Dec, ptxt[0]);
	if (Dec > p/2)
		Dec -= p;
	return Dec;
}
int main()
{
	int client_sockfd;  
	int len,len1;     
	struct sockaddr_in remote_addr; 
	char buf[BUFSIZ],buf1[BUFSIZ],buf2[BUFSIZ];  
	int lenbuf;
	long m = 0;          
	long p = 2147483647; 
	long r = 1;
	long L = 16;
	long c = 3;
	long w = 64;
	long d = 0;
	long k = 128;
	long s = 0;
	m = FindM(k, L, c, p, d, s, 0);
        int count=0;
	
	FHEcontext context(m, p, r);
	buildModChain(context, L, c);
	ZZX G = context.alMod.getFactorsOverZZ()[0];
	
	
	FHESecKey secretKey(context);
	const FHEPubKey& publicKey = secretKey;
	secretKey.GenSecKey(w);
	
       struct sockaddr_in client_addr;
       bzero(&client_addr, sizeof(client_addr));
       client_addr.sin_family = AF_INET;
       client_addr.sin_addr.s_addr = htons(INADDR_ANY);
       client_addr.sin_port = htons(0);
       int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
       if(client_socket_fd < 0)
       {
        perror("Create Socket Failed:");
        exit(1);
        }
	
    // 绑定客户端的socket和客户端的socket地址结构 非必需
       if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))
       {
        perror("Client Bind Failed:");
        exit(1);
       }
    // 声明一个服务器端的socket地址结构，并用服务器那边的IP地址及端口对其进行初始化，用于后面的连接
       struct sockaddr_in server_addr;
       bzero(&server_addr, sizeof(server_addr));
       server_addr.sin_family = AF_INET;
       if(inet_pton(AF_INET, "192.168.0.111", &server_addr.sin_addr) == 0)
       {
        perror("Server IP Address Error:");
        exit(1);
       }
       server_addr.sin_port = htons(SERVER_PORT);
       socklen_t server_addr_length = sizeof(server_addr);
	
    // 向服务器发起连接，连接成功后client_socket_fd代表了客户端和服务器的一个socket连接
      if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)
    {
        perror("Can Not Connect To Server IP:");
        exit(0);
    }
//-----------------------------------------------------------
    char file_name[FILE_NAME_MAX_SIZE+1];     //存放密文的文件
    bzero(file_name, FILE_NAME_MAX_SIZE+1);
    printf("Please Input cyper File Name On Server:\t");
    scanf("%s", file_name);
	
        char buffer[BUFFER_SIZE];
	printf("Please enter expression:\t");
	scanf("%s", buffer);               //buffer  a+a+a
	int n=strlen(buffer);
	for(int i=0;i<n;i++)
	{
		if('0'<=buffer[i]&&buffer[i]<='9')                                   //，存放到opnum数组中
		{
			count++; 
			opnum[count]=buffer[i]-'0';
			buffer[i]='a';                                  
		}
		send(client_sockfd,buffer,strlen(buffer),0);     //a+a+a
		/*char buffer1[100];
                char temp[]="#";
		fwrite(buffer1,sizeof(char),strlen(buffer1),fp);
		fwrite(temp,sizeof(char),strlen(temp),fp);*/
	}
//--------------------------------------------------------
	char ncount[2];
	ncount[0]=count;              //传走个数
	send(client_sockfd,ncount,sizeof(ncount),0);
//---------------------------------------------------------
        fstream keyFile(file_name, fstream::out|fstream::trunc);  
 for(int i=1;i<=count;i++)
        {
                       
               //打开这个文件准备写文件 
       		assert(keyFile.is_open());
		Ctxt Ea=FHE_Enc(opnum[i], publicKey);
		keyFile<<Ea;  
                keyFile<<'#';    
         } 
       keyFile.close();
//----------------------------------------------------------
        FILE *fp1 = fopen(file_name, "rb");      //打开文件传输
        bzero(buffer, BUFFER_SIZE);  
        int length = 0;  
            // 每读取一段数据，便将其发送给客户端，循环直到文件读完为止  
        while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp1)) > 0)  
        {  
             if(send(client_socket_fd, buffer, length, 0) < 0)  
                {  
                    printf("Send File:%s Failed./n", file_name);  
                    break;  
                }  
                bzero(buffer, BUFFER_SIZE);  
        }  
       //shutdown(client_socket_fd,1);      
       // recv(client_socket_fd,buffer,BUF_SIZE,0);
       fclose(fp1);
//-----------------接受密文结果并放到文件当中-------------------------------------
    FILE *fp2= fopen("result.txt", "wb");
    if(NULL==fp2)
    {
        printf("File:\t%s Can Not Open To Write\n", file_name);
        exit(1);
    }   
    else
    while((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)
    {
        if(fwrite(buffer, sizeof(char), length, fp2) < length)
        {
            printf("File:\t%s Write Failed\n", file_name);
            break;
        }
        bzero(buffer, BUFFER_SIZE);
    }
   fclose(fp2);
//------------------------------打开文件，读出---------------
     fstream key("result.txt",fstream::in);
     Ctxt Ec(publicKey);
     //Ctxt ctxt(publicKey);
     key>>Ec;
     key.close();
     printf("result:%ld\n",FHE_Dec(Ec, p, secretKey));  
     key.close();    

 
 close(client_socket_fd);
 return 0;  
}     
//------------------------------------------------------
    // 向服务器发送buffer中的数据
   /* if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)                    
    {
        perror("Send File Name Failed:");
        exit(1);
    }*/
	
	
    // 从服务器接收数据到buffer中
    // 每接收一段数据，便将其写入文件中，循环直到文件接收完并写完为止
   /* bzero(buffer, BUFFER_SIZE);
    int length = 0;
    while((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)
    {
        if(fwrite(buffer, sizeof(char), length, fp) < length)
        {
            printf("File:\t%s Write Failed\n", file_name);
            break;
        }
        bzero(buffer, BUFFER_SIZE);
    }*/
	
    // 接收成功后，关闭文件，关闭socket
    //printf("Receive File:\t%s From Server IP Successful!\n", file_name);
   // fclose(fp);
	//fstream keyF("clientans.txt",fstream::out|fstream::trunc);           //打开文件准备读入          
//	keyF<<buf2;
//	keyF.close();
	
	//fstream key("clientans.txt",fstream::in);
    //key>>Ec;
	//key.close();
	//printf("received:%s=%ld\n",buf1,FHE_Dec(Ec, p, secretKey));   
    //close(client_socket_fd);
    //return 0;
//}





 /*char buffer[BUFFER_SIZE];     
    char buffer1[BUFFER_SIZE];
    bzero(buffer, BUFFER_SIZE);
    strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));*/
 /*/fstream keyFile("iotest.txt", fstream::in);          
               //打开这个文件准备输出
       		//assert(keyFile.is_open());
		Ctxt Ea=FHE_Enc(opnum[i], publicKey);
		//keyFile<<*Ea;  
                //keyFile<<'#';                                 
		//fwrite(Ea,sizeof(char),strlen(Ea),fp);
		//fwrite(temp,sizeof(char),strlen(temp),fp);*/


//------------------------------------
/*打开文件，写入密文
	
          FILE *fp = fopen(file_name, "wb");
          char temp[10];
	  temp[0]='#';
          if(NULL == fp)
          {
             printf("File:\t%s Can Not Open To Write\n", file_name);
             exit(1);
           }
	  for(int i=1;i<=count;i++)
	{
            Ctxt Ea=FHE_Enc(opnum[i], publicKey);
           
         
	
	
        fwrite(buffer1,sizeof(char),strlen(buffer1),fp);
        fwrite(temp,sizeof(char),strlen(temp),fp);
	      
	}
         fclose(fp);*/
    
